#include "DefenseLineBehaviour.h"
#include "../../CommonFunctions.h"

//konstruktor
DefenseLineBehaviour::DefenseLineBehaviour()
{
	stredBrany = Point(-52.5, 0);
}

/*
 * Obranny mod brankara.
 * Ak sa lopta nachadza naboku od brany, brankar sa bud presunie na vhodnu poziciu
 * alebo ju len sleduje ak je na vhodnej pozicii. Ak nie je na vhodnej pozicii,
 * t.j. bud je moc vpredu alebo moc vzadu tak sa presunie na poziciu. Ak na nej
 * uz je tak len presuva bez toho aby otocil telom.
 */
void DefenseLineBehaviour::Behave()
{
	Vector goalball = world->ball->pos - stredBrany;
	G_TXT("  DefenseLine");
	//najprv si urcime odporucane postavenie hraca
	Point p;
	bool bLeft;
	DefensePoint(p, bLeft);
	//urcenie nebezpecenstva
	bool danger     = world->ball->pos.GetX() < -20.;
	bool big_danger = world->ball->pos.GetX() < -30.;

	//lopta prilis na boku
	if(world->ball->pos.GetX() < -46. ||
		(DATA_STORAGE.InPenaltyArea(world->ball->pos) && goalball.GetAngle().GetAbsDeg() > 60.))
	{
		if((fabsf(world->me->pos.GetY()) > 5.75) && (fabsf(world->me->pos.GetY()) < 6.5) &&
			((world->ball->pos.GetY() < 0.) == (world->me->pos.GetY() < 0.))) //posledna podmienka, ze sme na spravnej strane
		{
			if(world->me->pos.GetX() <= -51.)
			{
				if(TurnBody(bLeft, 10.))
				{
					//nie som na svojej pozicii
					G_TXTN(", turn body");
					return;
				}
				//som OK, len sa pozrem na loptu
				LookAtBall();
				return;
			}
			if(world->me->GetAbsDir().GetAbsDeg() > 10.)
			{
				//otocime sa smerom dopredu
				float turnMoment = GetRunToPositionBehaviour()->CompMoment(-world->me->GetAbsDir().GetDeg());
				GetTurnToBehaviour()->GoalieTurn(turnMoment);
				return;
			}
			//uz sme otoceny,len pekne pojdeme na svoju poziciu
			Point bestPoint;
			float dashPower = GetDashBehaviour()->GetBestDash(Point(-51., world->me->pos.GetY()),
				*world->me, bestPoint, 10.);
			GetDashBehaviour()->Behave(dashPower);
			return;
		}
		else
		{
			GetRunToPositionBehaviour()->Behave(Point(-51., world->ball->pos.GetY() < 0 ? -6.0f : 6.0f), true, true, 0.);
			return;
		}
	}
	//ak nie som v obrannej pozicii (som moc vpredu)
	if((!danger && world->me->pos.GetX() > DEFENSE_LINE_F) ||
		(danger && world->me->pos.GetX() > DEFENSE_LINE_F + 0.5f))
	{
		GetRunToPositionBehaviour()->BehaveBackwards(p, danger, big_danger, 0.);
		G_TXTN(", running: %d%d", danger, big_danger);
		return;
	}
	//ak nie som v obrannej pozicii (som moc vzadu)
	if((!danger && world->me->pos.GetX() < DEFENSE_LINE_B) ||
		(danger && world->me->pos.GetX() < (DEFENSE_LINE_B - 0.5f)))
	{
		GetRunToPositionBehaviour()->Behave(p, danger, big_danger, 0.);
		G_TXTN(", running: %d%d", danger, big_danger);
		return;
	}
	//uz som na svojej pozicii
	if(TurnBody(bLeft, danger ? 10.0f : 3.0f))
	{
		G_TXTN(", turn body");
		//cs_natocenie_dolava = bLeft;
		return;
	}
	//tak sa len posuniem, v ziadnom pripade neotacam telom, to je zabezpecene
	Point bestPoint;
	float dashPower = GetDashBehaviour()->GetBestDash(p, *world->me, bestPoint, 10.f);
	GetDashBehaviour()->Behave(dashPower);
	G_TXTN(", move %.2f,%.2f, DASH: %.2f", p.GetX(), p.GetY(), dashPower);
}


/*
 * funkcia vrati obrannu poziciu a ci sa lopta nachadza nalavo alebo napravo od stredu brany
 *
 * @param p obranna pozicia brankara
 * @param left ci sa lopta nachadza nalavo od stredu brany
 */
void DefenseLineBehaviour::DefensePoint(Point &p,bool &left)
{
	float x = world->me->pos.GetX();
	if(x < -48.5)
		x = -48.3f;
	if(x > -47.5)
		x = -47.7f;

	//lopta-stred
	p = Point(x, world->ball->pos.GetY() * (x - stredBrany.GetX()) / (world->ball->pos.GetX() - stredBrany.GetX()));
	if(p.GetY() < -6.)
		p.SetY(-6.);
	if(p.GetY() > 6.)
		p.SetY(6.);

	left = world->ball->pos.GetY() < 0;
}

/*
 * @param left ci sa lopta nachadza nalavo od stredu brany
 * @param odch odchylka natocenia
 *
 * @return funkcia vrati true, ak brankar sa musel natocit (cize, ak musel urobit prikaz)
 */
bool DefenseLineBehaviour::TurnBody(bool left, float odch)
{
	float uhol;
	if(left)
		uhol = -90.0;
	else
		uhol = 90.0;

	//ak som dobre natoceny, skonci
	if((uhol >= (world->me->GetAbsDir().GetDeg() - odch)) && ((uhol <= world->me->GetAbsDir().GetDeg() + odch)))
		return false;
	uhol -= world->me->GetAbsDir().GetDeg();
	float turnMoment = GetRunToPositionBehaviour()->CompMoment(uhol);
	GetTurnToBehaviour()->GoalieTurn(turnMoment);
	return true;
}

/*
 * ziadny prikaz, hrac sa pozrie za loptou
 */
void DefenseLineBehaviour::LookAtBall()
{
	Ball tmpBall(*world->ball); tmpBall.Step();
	GetTurnNeckToBehaviour()->Behave(tmpBall.pos, world->me->pos + world->me->vel);
}
